﻿#region << 文 件 说 明 >>

/*----------------------------------------------------------------
// 文件名称：BillVM
// 创 建 者：杨程
// 创建时间：2022/2/7 10:02:40
// 文件版本：V1.0.0
// ===============================================================
// 功能描述：
//
//
//----------------------------------------------------------------*/

#endregion

namespace Vampirewal.Core.SimpleMVVM;

/// <summary>
/// 单据基本信息页VM
/// <para>基本功能：</para>
/// <para>1、打开一个单据，框架会自动创建一个空的Entity</para>
/// <para>2、可通过在构造函数中调用<typeparamref name="GetById方法"/>来获取当前的基本信息数据</para>
/// <para>3、如果自身存在N个关联的明细数据，可通过调用<typeparamref name="GetDetail方法"/>来获取数据</para>
/// </summary>
public abstract partial class BillVM<TEntity> : ViewModelBase where TEntity : BillBaseModel, new()
{
    #region 构造函数

    public BillVM(SqlSugarRepository<TEntity> rep) : base()
    {
        if (Entity == null)
        {
            var ctor = typeof(TEntity).GetConstructor(Type.EmptyTypes);
            Entity = ctor.Invoke(null) as TEntity;
        }

        Rep = rep;
        BillVmInitData();
    }

    public BillVM() : base()
    {
        if (Entity == null)
        {
            var ctor = typeof(TEntity).GetConstructor(Type.EmptyTypes);
            Entity = ctor.Invoke(null) as TEntity;
        }

        BillVmInitData();
    }

    #endregion

    #region 属性

    /// <summary>
    /// 单据基本信息实体类
    /// </summary>
    [ObservableProperty]
    private TEntity entity;

    protected SqlSugarRepository<TEntity> Rep { get; set; }

    #endregion

    #region 公共方法

    /// <summary>
    /// 直连数据库的话需要通过调用该方法获取Entity
    /// <para>★通过其他方式获取数据的话，需重写★</para>
    /// </summary>
    /// <param name="BillId"></param>
    protected virtual void GetById(string BillId)
    {
        Entity = Rep.Single(w => w.BillId == BillId);
    }

    /// <summary>
    /// 通过HttpClient等方式获取的Entity可调用该方法赋值
    /// </summary>
    /// <param name="t"></param>
    protected void SetEntity(TEntity t)
    {
        if (t != null)
            Entity = t;
    }

    /// <summary>
    /// 获取该单据的明细数据
    /// </summary>
    /// <typeparam name="TDetail">明细类型</typeparam>
    /// <param name="Success">成功之后的执行的方法</param>
    /// <param name="Fail">异常之后执行的方法</param>
    /// <param name="CustomQueryable">自定义查询条件</param>
    /// <exception cref="Exception"></exception>
    protected void GetDetail<TDetail>(Action<List<TDetail>> Success = null, Action<Exception> Fail = null, string DbName = "default", Expression<Func<TDetail, bool>> CustomQueryable = null)
        where TDetail : DetailBaseModel, new()
    {
        if (DbName != "default")
        {
            Rep.Context.ChangeDatabase(DbName);
        }

        try
        {
            List<TDetail> list = null;

            if (CustomQueryable == null)
            {
                list = Rep.Change<TDetail>().ToList(w => w.BillId == Entity.BillId);
            }
            else
            {
                list = Rep.Change<TDetail>().AsQueryable(CustomQueryable).ToList();
            }

            Success?.Invoke(list);
        }
        catch (Exception ex)
        {
            Fail?.Invoke(ex);
        }
        finally
        {
            Rep.Context.ChangeDatabase("default");
        }
    }

    /// <summary>
    /// 获取任意数据填充到List
    /// </summary>
    /// <typeparam name="TModel">实体模型</typeparam>
    /// <param name="CustomQueryable">自定义查询条件</param>
    /// <param name="Success">成功之后的执行的方法</param>
    /// <param name="Fail">异常之后执行的方法</param>
    /// <param name="DbName">数据库名称</param>
    /// <exception cref="Exception"></exception>
    protected void GetList<TModel>(Expression<Func<TModel, bool>> CustomQueryable, Action<List<TModel>> Success, Action<Exception> Fail, string DbName = "default") where TModel : TopModel, new()
    {
        if (DbName != "default")
        {
            Rep.Context.ChangeDatabase(DbName);
        }
        try
        {
            List<TModel> list = Rep.Change<TModel>().AsQueryable(CustomQueryable).ToList();

            Success?.Invoke(list);
        }
        catch (Exception ex)
        {
            Fail?.Invoke(ex);
        }
        finally
        {
            Rep.Context.ChangeDatabase("default");
        }
    }

    #endregion

    #region 私有方法

    /// <summary>
    /// 验证数据库连接
    /// </summary>
    /// <param name="DbName"></param>
    /// <exception cref="Exception"></exception>
    private void CheckClient(string DbName)
    {
        if (DbName != "default")
        {
            Rep.Context.ChangeDatabase(DbName);
        }
    }

    private void DoCRUD(string OperationCommand)
    {
        Rep.BeginTran();
        try
        {
            switch (OperationCommand)
            {
                case "add":
                    Rep.Insert(Entity);
                    break;

                case "update":
                    Rep.Update(Entity);
                    break;

                case "delete":
                    {
                        Type type = typeof(TEntity);

                        var Interfaces = type.GetInterface("IPersistModel");

                        if (Interfaces != null)
                        {
                            (Entity as IPersistModel).IsDelete = true;
                            Rep.Update(Entity);
                        }
                        else
                        {
                            Entity.UpdateBy = VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName) == true ? UserName.ToString() : "";
                            Entity.UpdateUserId = VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId) == true ? UserId.ToString() : "";
                            Entity.UpdateTime = DateTime.Now;
                            Rep.Delete(Entity);
                        }
                    }

                    break;
            }

            Rep.CommitTran();
        }
        catch
        {
            Rep.RollbackTran();
        }
        finally
        {
            Rep.Context.ChangeDatabase("default");
        }
    }

    private async Task DoCRUDasync(string OperationCommand)
    {
        Rep.BeginTran();
        try
        {
            switch (OperationCommand)
            {
                case "add":
                    await Rep.InsertAsync(Entity);
                    break;

                case "update":
                    await Rep.UpdateAsync(Entity);
                    break;

                case "delete":
                    {
                        Type type = typeof(TEntity);

                        var Interfaces = type.GetInterface("IPersistModel");

                        if (Interfaces != null)
                        {
                            (Entity as IPersistModel).IsDelete = true;
                            await Rep.UpdateAsync(Entity);
                        }
                        else
                        {
                            Entity.UpdateBy = VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName) == true ? UserName.ToString() : "";
                            Entity.UpdateUserId = VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId) == true ? UserId.ToString() : "";
                            Entity.UpdateTime = DateTime.Now;
                            await Rep.DeleteAsync(Entity);
                        }
                    }

                    break;
            }

            Rep.CommitTran();
        }
        catch
        {
            Rep.RollbackTran();
        }
        finally
        {
            Rep.Context.ChangeDatabase("default");
        }
    }

    #endregion

    #region 重写

    /// <summary>
    /// BillVM的数据化方法
    /// </summary>
    public virtual void BillVmInitData()
    {
    }

    /// <summary>
    /// 执行entity的新增到数据库操作
    /// </summary>
    /// <param name="DbName"></param>
    public virtual void DoAdd(string DbName = "default")
    {
        CheckClient(DbName);

        //Entity.CreateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode;

        DoCRUD("add");
    }

    /// <summary>
    /// 异步执行entity的新增到数据库操作
    /// </summary>
    /// <param name="DbName"></param>
    public virtual async void DoAddAsync(string DbName = "default")
    {
        CheckClient(DbName);

        //Entity.CreateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode;

        await DoCRUDasync("add");
    }

    /// <summary>
    /// 执行entity的修改到数据库操作
    /// </summary>
    /// <param name="DbName"></param>
    public virtual void DoUpdate(string DbName = "default")
    {
        CheckClient(DbName);

        //Entity.UpdateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode;

        DoCRUD("update");
    }

    /// <summary>
    /// 异步执行entity的修改到数据库操作
    /// </summary>
    /// <param name="DbName"></param>
    public virtual async void DoUpdateAsync(string DbName = "default")
    {
        CheckClient(DbName);

        //Entity.UpdateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode;

        await DoCRUDasync("update");
    }

    /// <summary>
    /// 执行entity的删除到数据库操作
    /// </summary>
    /// <param name="DbName"></param>
    public virtual void DoDelete(string DbName = "default")
    {
        CheckClient(DbName);

        DoCRUD("delete");
    }

    /// <summary>
    /// 异步执行entity的删除到数据库操作
    /// </summary>
    /// <param name="DbName"></param>
    public virtual async void DoDeleteAsync(string DbName = "default")
    {
        CheckClient(DbName);

        await DoCRUDasync("delete");
    }

    /// <summary>
    /// 修改明细
    /// </summary>
    /// <typeparam name="TDetail"></typeparam>
    /// <param name="DataSource"></param>
    /// <param name="DbName"></param>
    public virtual void UpdateDetail<TDetail>(List<TDetail> DataSource, string DbName = "default") where TDetail : DetailBaseModel, new()
    {
        CheckClient(DbName);
        Rep.Change<TDetail>().BeginTran();
        try
        {
            if (DataSource.Count > 1000)
            {
                Rep.Change<TDetail>().Context.Fastest<TDetail>().PageSize(1000).BulkUpdate(DataSource);
            }
            else
            {
                Rep.Change<TDetail>().Update(DataSource);
            }

            Rep.Change<TDetail>().CommitTran();
        }
        catch
        {
            Rep.RollbackTran();
        }
        finally
        {
            Rep.Context.ChangeDatabase("default");
        }
    }

    /// <summary>
    /// 添加明细数据
    /// </summary>
    /// <typeparam name="TDetail"></typeparam>
    /// <param name="DataSource"></param>
    /// <param name="DbName"></param>
    public virtual void AddDetail<TDetail>(List<TDetail> DataSource, string DbName = "default") where TDetail : DetailBaseModel, new()
    {
        CheckClient(DbName);

        Rep.BeginTran();
        try
        {
            if (DataSource.Count > 1000)
            {
                Rep.Change<TDetail>().Context.Fastest<TDetail>().PageSize(1000).BulkCopy(DataSource);
            }
            else
            {
                Rep.Change<TDetail>().Insert(DataSource);
            }

            Rep.Change<TDetail>().CommitTran();
        }
        catch
        {
            Rep.RollbackTran();
        }
        finally
        {
            Rep.Context.ChangeDatabase("default");
        }
    }

    /// <summary>
    /// 删除明细数据
    /// </summary>
    /// <typeparam name="TDetail"></typeparam>
    /// <param name="DataSource"></param>
    /// <param name="DbName"></param>
    public virtual void DeleteDetail<TDetail>(List<TDetail> DataSource, string DbName = "default") where TDetail : DetailBaseModel, new()
    {
        CheckClient(DbName);

        try
        {
            Rep.Change<TDetail>().BeginTran();

            Rep.Change<TDetail>().Delete(DataSource);

            Rep.Change<TDetail>().CommitTran();
        }
        catch
        {
            Rep.Change<TDetail>().RollbackTran();
        }
        finally
        {
            Rep.Context.ChangeDatabase("default");
        }
    }

    #endregion
}